// @Author: cyl
// @File: main.go
// @Time: 2023/07/03 23:03:32
package main

import (
	"context"
	"sync"
	"time"
)

/**
1、考题1: 实现一个map
(1) 面向高并发
(2) 只存在插入和查询操作
(3) 查询时，若key存在直接返回val; 若key不存在，阻塞直到key val键值队被放入后获取val返回；等待指定时长仍未放入，返回超时错误
(4) 写出真实代码，不能有死锁或panic风险
*/

type MyConcurrentMap struct {
	sync.Mutex
	mp      map[int]int
	keyToCh map[int]chan struct{}
}

func NewMyConcurrentMap() *MyConcurrentMap {
	return &MyConcurrentMap{
		mp:      make(map[int]int, 0),
		keyToCh: make(map[int]chan struct{}),
	}
}

func (m *MyConcurrentMap) Put(k, v int) {
	m.Lock()
	defer m.Unlock()
	m.mp[k] = v

	ch, ok := m.keyToCh[k]
	if !ok {
		return
	}
	// ch <- struct{}{}
	// 解决ch重复关闭问题方式1: 再读一次
	select {
	case <-ch:
		return
	default:
		close(ch)
	}
}

func (m *MyConcurrentMap) Get(k int, maxWaitingDuration time.Duration) (int, error) {
	m.Lock()
	v, ok := m.mp[k]
	if ok {
		m.Unlock()
		return v, nil
	}

	ch, ok := m.keyToCh[k]
	if !ok {
		ch = make(chan struct{})
		m.keyToCh[k] = ch
	}

	tCtx, cancel := context.WithTimeout(context.Background(), maxWaitingDuration)
	defer cancel()

	m.Unlock()

	select {
	case <-tCtx.Done():
		return -1, tCtx.Err()
	case <-ch:
	}

	m.Lock()
	v = m.mp[k]
	m.Unlock()
	return v, nil
}
